package com.tracelog.core.config;

import com.tracelog.core.aspect.TraceLogAspect;
import com.tracelog.core.dao.DefaultLogRecordDao;
import com.tracelog.core.dao.LogRecordDao;
import com.tracelog.core.filter.RequestBodyCacheFilter;
import com.tracelog.core.filter.TraceMdcFilter;
import com.tracelog.core.handler.DefaultLogHandler;
import com.tracelog.core.handler.LogHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.scheduling.annotation.EnableAsync;

/**
 * TraceLog自动配置
 *
 * @author tracelog
 * @since 1.0.0
 */
@Slf4j
@Configuration
@EnableAsync
@EnableConfigurationProperties(TraceLogProperties.class)
@ConditionalOnProperty(prefix = "trace-log", name = "enabled", havingValue = "true", matchIfMissing = true)
public class TraceLogAutoConfiguration {

    /**
     * 日志处理器
     *
     * @param properties 配置属性
     * @return 日志处理器
     */
    @Bean
    @ConditionalOnMissingBean
    public LogHandler logHandler(TraceLogProperties properties) {
        log.info("Initializing TraceLog Handler");
        return new DefaultLogHandler(properties);
    }

    /**
     * 日志存储
     *
     * @param properties 配置属性
     * @return 日志存储
     */
    @Bean
    @ConditionalOnMissingBean
    public LogRecordDao logRecordDao(TraceLogProperties properties) {
        log.info("Initializing TraceLog DAO");
        return new DefaultLogRecordDao(properties);
    }

    /**
     * 日志切面
     *
     * @param logHandler  日志处理器
     * @param logRecordDao 日志存储
     * @return 日志切面
     */
    @Bean
    @ConditionalOnMissingBean
    public TraceLogAspect traceLogAspect(LogHandler logHandler, LogRecordDao logRecordDao) {
        log.info("Initializing TraceLog Aspect");
        return new TraceLogAspect(logHandler, logRecordDao);
    }
    
    /**
     * 请求体缓存过滤器
     *
     * @return 过滤器注册Bean
     */
    @Bean
    @ConditionalOnProperty(prefix = "trace-log", name = "cache-request-body", havingValue = "true", matchIfMissing = true)
    public FilterRegistrationBean<RequestBodyCacheFilter> requestBodyCacheFilter() {
        log.info("Initializing TraceLog Request Body Cache Filter");
        FilterRegistrationBean<RequestBodyCacheFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new RequestBodyCacheFilter());
        registrationBean.addUrlPatterns("/*");
        registrationBean.setName("requestBodyCacheFilter");
        registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return registrationBean;
    }
    
    /**
     * MDC跟踪过滤器
     *
     * @return 过滤器注册Bean
     */
    @Bean
    @ConditionalOnProperty(prefix = "trace-log", name = "enable-trace-id", havingValue = "true", matchIfMissing = true)
    public FilterRegistrationBean<TraceMdcFilter> traceMdcFilter() {
        log.info("Initializing TraceLog MDC Filter");
        FilterRegistrationBean<TraceMdcFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new TraceMdcFilter());
        registrationBean.addUrlPatterns("/*");
        registrationBean.setName("traceMdcFilter");
        registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);  // 在请求体缓存过滤器之后执行
        return registrationBean;
    }
} 